<?php

namespace Muyuxuanpay\threePay\src\cj\protocolPayment;

use Muyuxuanpay\threePay\BaseTrait;
use Muyuxuanpay\threePay\ProtocolPaymentPay;
use Muyuxuanpay\threePay\src\cj\CommonTrait;

/**
 * 协议支付
 */
class Pay implements ProtocolPaymentPay
{
    use BaseTrait;
    use CommonTrait;
    protected $must = [
        'merchant_id'=>"商户编号",
        'product_code'=>"营销产品编码",
        'function_code'=>"基础产品编码",
        'public_key'=>"公钥",
        'private_key'=>"秘钥",
    ];
    protected $defaultConfig = [
        'format'=>'JSON',
        'charset'=>'UTF-8',
        'sign_type'=>'RSA2',
        'version'=>'1.0',
    ];//配置
    //证件类型
    protected $typeList = [
        '身份证'=>'01',
        '军官证'=>'02',
        '护照'=>'03',
        '户口簿'=>'04',
        '士兵证'=>'05',
        '港澳通行证'=>'06',
        '台胞通行证'=>'07',
        '临时身份证'=>'08',
        '外国人居留证'=>'09',
        '警官证'=>'10',
        '其他'=>'99',
    ];
    /**
     * 预签约
     * @param string $out_trade_no 商户订单号
     * @param string $id_crad_no 证件号码
     * @param string $id_crad_type 证件类型
     * @param string $card_name 留卡名
     * @param string $mobile 手机号
     * @param string $card_no 银行卡号
     * @param string $notify_url 回调
     * @param $event [card_exp_date=YYYYMMDD] 卡有效期[card_cvv=3位] 卡CVV
     * @return mixed
     * @throws \Exception
     */
    public function preContract(string $out_trade_no,string $id_crad_no,string $id_crad_type,string $card_name,string $mobile,string $card_no,string $notify_url='',array $event=[])
    {
        //验证参数
        $this->verify();
        $now = date('YmdHis');
        if(!is_numeric($id_crad_type)){
            if(is_array($id_crad_type)){
                throw new \Exception('id_crad_type参数类型错误');
            }
            if(empty($this->typeList[$id_crad_type])){
                throw new \Exception('id_crad_type参数类型错误');
            }
            $id_crad_type = $this->typeList[$id_crad_type];
        }
        $msgCiphertext = [
            'out_trade_no'=>$out_trade_no,
            'id_crad'=>$id_crad_no,
            'id_crad_type'=>$id_crad_type,
            'card_name'=>$card_name,
            'mobile'=>$mobile,
            'card_no'=>$card_no,
            'notify_url'=>$notify_url,
        ];
        if(!empty($event)){
            $msgCiphertext = array_merge($msgCiphertext,$event);
        }
        $requestData = [
            'method'        => 'chanpay.merchanttrade.quickpay.presign',
            'merchant_id'   => $this->config['merchant_id'],
            'product_code'  => $this->config['product_code'],
            'function_code' =>$this->config['function_code'],
            'format'        => $this->defaultConfig['format'],
            'charset'       =>  $this->defaultConfig['charset'],
            'sign_type'     =>$this->defaultConfig['sign_type'],
            'version'       => $this->defaultConfig['version'],
            'timestamp'     => $now,
            'biz_content'   => $this->getEncryptionRequestBody($msgCiphertext, $this->config['public_key']),
        ];
        $requestData['sign'] = $this->getSign($requestData, $this->config['private_key']);
        $requestRus = $this->post($this->URL['wx_pub'], $requestData);
        if($requestRus['code']!='00000'){
            $msg = $requestRus['msg']?$requestRus['msg']:($requestRus['sub_msg']?$requestRus['sub_msg']:'请求失败');
            throw new \Exception($msg);
        }
        if(isset($requestRus['sub_code'])&&$requestRus['sub_code']=='FAIL'){
            throw new \Exception($requestRus['sub_msg']);
        }
        return $requestRus;
    }

    /**
     * 确认签约
     * @param string $out_trade_no 商户订单号
     * @param string $presign_seq_no 订单流水号
     * @param string $sms_code 短信验证码
     * @return mixed
     * @throws \Exception
     */
    public function contractConfirm(string $out_trade_no,string $presign_seq_no,string $sms_code)
    {
        $now = date('YmdHis');
        $this->verify();
        $msgCiphertext = [
            'out_trade_no'=>$out_trade_no,
            'presign_seq_no'=>$presign_seq_no,
            'sms_code'=>$sms_code,
        ];
        $requestData = [
            'method'        => 'chanpay.merchanttrade.quickpay.sign',
            'merchant_id'   => $this->config['merchant_id'],
            'product_code'  => $this->config['product_code'],
            'function_code' =>$this->config['function_code'],
            'format'        => $this->defaultConfig['format'],
            'charset'       =>  $this->defaultConfig['charset'],
            'sign_type'     =>$this->defaultConfig['sign_type'],
            'version'       => $this->defaultConfig['version'],
            'timestamp'     => $now,
            'biz_content'   => $this->getEncryptionRequestBody($msgCiphertext, $this->config['public_key']),
        ];
        $requestData['sign'] = $this->getSign($requestData, $this->config['private_key']);
        $requestRus = $this->post($this->URL['wx_pub'], $requestData);
        if($requestRus['code']!='00000'){
            $msg = $requestRus['msg']?$requestRus['msg']:($requestRus['sub_msg']?$requestRus['sub_msg']:'请求失败');
            throw new \Exception($msg);
        }
        if(isset($requestRus['sub_code'])&&$requestRus['sub_code']=='FAIL'){
            throw new \Exception($requestRus['sub_msg']);
        }
        return $requestRus;
    }

    /**
     * 查询签约
     * @param string $out_trade_no 商户订单号
     * @param string|null $chanpay_trade_no 畅捷订单号
     * @param array $event [remark=备注信息]
     * @return mixed
     * @throws \Exception
     */
    public function contractQuery(string $out_trade_no,?string $chanpay_trade_no=null,array $event=[])
    {
        $now = date('YmdHis');
        $this->verify();
        $msgCiphertext = [
            'out_trade_no'=>$out_trade_no
        ];
        if(!empty($chanpay_trade_no)){
            $msgCiphertext['chanpay_trade_no'] = $chanpay_trade_no;
        }
        $requestData = [
            'method'        => 'chanpay.merchanttrade.quickpay.agrtquery',
            'merchant_id'   => $this->config['merchant_id'],
            'product_code'  => $this->config['product_code'],
            'function_code' =>$this->config['function_code'],
            'format'        => $this->defaultConfig['format'],
            'charset'       =>  $this->defaultConfig['charset'],
            'sign_type'     =>$this->defaultConfig['sign_type'],
            'version'       => $this->defaultConfig['version'],
            'timestamp'     => $now,
            'biz_content'   => $this->getEncryptionRequestBody($msgCiphertext, $this->config['public_key']),
        ];
        $requestData['sign'] = $this->getSign($requestData, $this->config['private_key']);
        $requestRus = $this->post($this->URL['wx_pub'], $requestData);
        if($requestRus['code']!='00000'){
            $msg = $requestRus['msg']?$requestRus['msg']:($requestRus['sub_msg']?$requestRus['sub_msg']:'请求失败');
            throw new \Exception($msg);
        }
        if(isset($requestRus['sub_code'])&&$requestRus['sub_code']=='FAIL'){
            throw new \Exception($requestRus['sub_msg']);
        }
        return $requestRus;
    }

    /**
     * 解约
     * @param string $out_trade_no 商户订单号
     * @param string $sign_id 协议号
     * @param string $sign_acct_shrt_id 协议账户短号(银行账户后4位)
     * @return mixed
     * @throws \Exception
     */
    public function unContract(string $out_trade_no,string $sign_id,string $sign_acct_shrt_id='',array $event=[])
    {
        $now = date('YmdHis');
        $this->verify();
        $msgCiphertext = [
            'out_trade_no'=>$out_trade_no,
            'sign_id'=>$sign_id,
            'sign_acct_shrt_id'=>$sign_acct_shrt_id,
        ];
        $requestData = [
            'method'        => 'chanpay.merchanttrade.quickpay.verifycode.send',
            'merchant_id'   => $this->config['merchant_id'],
            'product_code'  => $this->config['product_code'],
            'function_code' =>$this->config['function_code'],
            'format'        => $this->defaultConfig['format'],
            'charset'       =>  $this->defaultConfig['charset'],
            'sign_type'     =>$this->defaultConfig['sign_type'],
            'version'       => $this->defaultConfig['version'],
            'timestamp'     => $now,
            'biz_content'   => $this->getEncryptionRequestBody($msgCiphertext, $this->config['public_key']),
        ];
        $requestData['sign'] = $this->getSign($requestData, $this->config['private_key']);
        $requestRus = $this->post($this->URL['wx_pub'], $requestData);
        if($requestRus['code']!='00000'){
            $msg = $requestRus['msg']?$requestRus['msg']:($requestRus['sub_msg']?$requestRus['sub_msg']:'请求失败');
            throw new \Exception($msg);
        }
        if(isset($requestRus['sub_code'])&&$requestRus['sub_code']=='FAIL'){
            throw new \Exception($requestRus['sub_msg']);
        }
        return $requestRus;
    }

    /**
     * 发送短信
     * @param string $sign_id 签约ID
     * @return mixed
     * @throws \Exception
     */
    public function sendSms(string $sign_id)
    {
        $now = date('YmdHis');
        $this->verify();
        $msgCiphertext = [
            'sign_id'=>$sign_id,
        ];
        $requestData = [
            'method'        => 'chanpay.merchanttrade.quickpay.verifycode.send',
            'merchant_id'   => $this->config['merchant_id'],
            'product_code'  => $this->config['product_code'],
            'function_code' =>$this->config['function_code'],
            'format'        => $this->defaultConfig['format'],
            'charset'       =>  $this->defaultConfig['charset'],
            'sign_type'     =>$this->defaultConfig['sign_type'],
            'version'       => $this->defaultConfig['version'],
            'timestamp'     => $now,
            'biz_content'   => $this->getEncryptionRequestBody($msgCiphertext, $this->config['public_key']),
        ];
        $requestData['sign'] = $this->getSign($requestData, $this->config['private_key']);
        $requestRus = $this->post($this->URL['wx_pub'], $requestData);
        if($requestRus['code']!='00000'){
            $msg = $requestRus['msg']?$requestRus['msg']:($requestRus['sub_msg']?$requestRus['sub_msg']:'请求失败');
            throw new \Exception($msg);
        }
        if(isset($requestRus['sub_code'])&&$requestRus['sub_code']=='FAIL'){
            throw new \Exception($requestRus['sub_msg']);
        }
        return $requestRus;
    }

    /**
     * 快捷支付
     * @param string $out_trade_no 商户订单号
     * @param string $sign_id 签约协议号
     * @param string|int|float $total_amount 订单金额
     * @param string $body 订单描述
     * @param array $event [sms_pay_code=短信验证码][remark=备注信息][notify_url=回调地址]
     * @return mixed
     * @throws \Exception
     */
    public function quickPay(string $out_trade_no,string $sign_id,$total_amount,string $body='',array $event=[])
    {
        $now = date('YmdHis');
        $this->verify();
        $msgCiphertext = [
            'out_trade_no'=>$out_trade_no,
            'sign_id'=>$sign_id,
            'total_amount'=>intval($total_amount*100),
            'trade_memo'=>$body,
        ];
        if(!empty($event)){
            $msgCiphertext = array_merge($msgCiphertext,$event);
        }
        $requestData = [
            'method'        => 'chanpay.merchanttrade.quickpay',
            'merchant_id'   => $this->config['merchant_id'],
            'product_code'  => $this->config['product_code'],
            'function_code' =>$this->config['function_code'],
            'format'        => $this->defaultConfig['format'],
            'charset'       =>  $this->defaultConfig['charset'],
            'sign_type'     =>$this->defaultConfig['sign_type'],
            'version'       => $this->defaultConfig['version'],
            'timestamp'     => $now,
            'biz_content'   => $this->getEncryptionRequestBody($msgCiphertext, $this->config['public_key']),
        ];
        $requestData['sign'] = $this->getSign($requestData, $this->config['private_key']);
        $requestRus = $this->post($this->URL['wx_pub'], $requestData);
        if($requestRus['code']!='00000'){
            $msg = $requestRus['msg']?$requestRus['msg']:($requestRus['sub_msg']?$requestRus['sub_msg']:'请求失败');
            throw new \Exception($msg);
        }
        if(isset($requestRus['sub_code'])&&$requestRus['sub_code']=='FAIL'){
            throw new \Exception($requestRus['sub_msg']);
        }
        return $requestRus;
    }

    /**
     * 订单查询
     * @param string $out_trade_no 订单号
     * @param string|null $chanpay_trade_no 畅捷订单号
     * @return mixed
     * @throws \Exception
     */
    public function orderQuery(string $out_trade_no,?string $chanpay_trade_no=null,array $event=[])
    {
        $now = date('YmdHis');
        $this->verify();
        $msgCiphertext = [
            'out_trade_no'=>$out_trade_no,
        ];
        if(!empty($chanpay_trade_no)){
            $msgCiphertext['chanpay_trade_no'] = $chanpay_trade_no;
        }
        $requestData = [
            'method'        => 'chanpay.merchanttrade.quickpay.query',
            'merchant_id'   => $this->config['merchant_id'],
            'product_code'  => $this->config['product_code'],
            'function_code' =>$this->config['function_code'],
            'format'        => $this->defaultConfig['format'],
            'charset'       =>  $this->defaultConfig['charset'],
            'sign_type'     =>$this->defaultConfig['sign_type'],
            'version'       => $this->defaultConfig['version'],
            'timestamp'     => $now,
            'biz_content'   => $this->getEncryptionRequestBody($msgCiphertext, $this->config['public_key']),
        ];
        $requestData['sign'] = $this->getSign($requestData, $this->config['private_key']);
        $requestRus = $this->post($this->URL['wx_pub'], $requestData);
        if($requestRus['code']!='00000'){
            $msg = $requestRus['msg']?$requestRus['msg']:($requestRus['sub_msg']?$requestRus['sub_msg']:'请求失败');
            throw new \Exception($msg);
        }
        if(isset($requestRus['sub_code'])&&$requestRus['sub_code']=='FAIL'){
            throw new \Exception($requestRus['sub_msg']);
        }
        return $requestRus;
    }

    /**
     * 退款
     * @param string $out_trade_no  支付订单号
     * @param string $out_refund_no 退款订单号
     * @param string|int|float $refund_amount 退款金额
     * @param string|null $chanpay_trade_no 畅捷订单号
     * @return mixed
     * @throws \Exception
     */
    public function refundOrder(string $out_trade_no,string $out_refund_no,$refund_amount,?string $chanpay_trade_no=null,array $event=[])
    {
        $now = date('YmdHis');
        $this->verify();
        $msgCiphertext = [
            'out_trade_no'=>$out_trade_no,
            'out_refund_no'=>$out_refund_no,
            'refund_amount'=>intval($refund_amount*100),
        ];
        if(!empty($chanpay_trade_no)){
            $msgCiphertext['chanpay_trade_no'] = $chanpay_trade_no;
        }
        $requestData = [
            'method'        => 'chanpay.merchanttrade.quickpay.refund',
            'merchant_id'   => $this->config['merchant_id'],
            'product_code'  => $this->config['product_code'],
            'function_code' =>$this->config['function_code'],
            'format'        => $this->defaultConfig['format'],
            'charset'       =>  $this->defaultConfig['charset'],
            'sign_type'     =>$this->defaultConfig['sign_type'],
            'version'       => $this->defaultConfig['version'],
            'timestamp'     => $now,
            'biz_content'   => $this->getEncryptionRequestBody($msgCiphertext, $this->config['public_key']),
        ];
        $requestData['sign'] = $this->getSign($requestData, $this->config['private_key']);
        $requestRus = $this->post($this->URL['wx_pub'], $requestData);
        if($requestRus['code']!='00000'){
            $msg = $requestRus['msg']?$requestRus['msg']:($requestRus['sub_msg']?$requestRus['sub_msg']:'请求失败');
            throw new \Exception($msg);
        }
        if(isset($requestRus['sub_code'])&&$requestRus['sub_code']=='FAIL'){
            throw new \Exception($requestRus['sub_msg']);
        }
        return $requestRus;
    }

    /**
     * 退款查询
     * @param string $out_trade_no 支付订单号
     * @param string $out_refund_no 退款订单号
     * @param string|null $chanpay_trade_no 畅捷订单号
     * @param string|null $chanpay_refund_no 畅捷退款订单号
     * @return mixed
     * @throws \Exception
     */
    public function refundQuery(string $out_trade_no,string $out_refund_no,?string $chanpay_trade_no=null,?string $chanpay_refund_no = null)
    {
        $now = date('YmdHis');
        $this->verify();
        $msgCiphertext = [
            'out_trade_no'=>$out_trade_no,
            'out_refund_no'=>$out_refund_no,
        ];
        if(!empty($chanpay_refund_no)){
            $msgCiphertext['chanpay_refund_no'] = $chanpay_refund_no;
        }
        if(!empty($chanpay_trade_no)){
            $msgCiphertext['chanpay_trade_no'] = $chanpay_trade_no;
        }
        $requestData = [
            'method'        => 'chanpay.merchanttrade.quickpay.refundquery',
            'merchant_id'   => $this->config['merchant_id'],
            'product_code'  => $this->config['product_code'],
            'function_code' =>$this->config['function_code'],
            'format'        => $this->defaultConfig['format'],
            'charset'       =>  $this->defaultConfig['charset'],
            'sign_type'     =>$this->defaultConfig['sign_type'],
            'version'       => $this->defaultConfig['version'],
            'timestamp'     => $now,
            'biz_content'   => $this->getEncryptionRequestBody($msgCiphertext, $this->config['public_key']),
        ];
        $requestData['sign'] = $this->getSign($requestData, $this->config['private_key']);
        $requestRus = $this->post($this->URL['wx_pub'], $requestData);
        if($requestRus['code']!='00000'){
            $msg = $requestRus['msg']?$requestRus['msg']:($requestRus['sub_msg']?$requestRus['sub_msg']:'请求失败');
            throw new \Exception($msg);
        }
        if(isset($requestRus['sub_code'])&&$requestRus['sub_code']=='FAIL'){
            throw new \Exception($requestRus['sub_msg']);
        }
        return $requestRus;
    }
}